package java_basic.JUC;

/**
 * i++为什么不能保证原子性?
 * 对volatile变量的单次读/写操作可以保证原子性的，如long和double类型变量，
 * 但是并不能保证i++这种操作的原子性，因为本质上i++是读、写两次操作。
 */
public class VolatileTest01 {
    volatile int i;

    public void addI(){
        i++;
    }

    public static void main(String[] args) throws InterruptedException {
        final  VolatileTest01 test01 = new VolatileTest01();
        for (int n = 0; n < 1000; n++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized(test01) {
                        test01.addI();
                    }
                }
            }).start();
        }
        Thread.sleep(10000);//等待10秒，保证上面程序执行完成
        System.out.println(test01.i);
    }
}


/**
 * 大家可能会误认为对变量i加上关键字volatile后，这段程序就是线程安全的。
 * 大家可以尝试运行上面的程序。下面是我本地运行的结果：981 可能每个人运行的结果不相同。
 * 不过应该能看出，volatile是无法保证原子性的(否则结果应该是1000)。原因也很简单，i++其实是一个复合操作，包括三步骤：读取i的值。对i加1。将i的值写回内存。 
 * volatile是无法保证这三个操作是具有原子性的，我们可以通过AtomicInteger或者Synchronized来保证+1操作的原子性。 
 * 注：上面几段代码中多处执行了Thread.sleep()方法，目的是为了增加并发问题的产生几率，无其他作用。#
 */